package com.gary.spring.cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;

/**
 * cglib 生成的动态代理类 : 通过 AWS 生成字节码
 *  使用MethodInterceptor 增强方法，将增强逻辑交给程序员实现   类似模板方法
 * @author peng_rui
 * @date 2022/7/4
 */
public class Proxy extends Target {

    private MethodInterceptor methodInterceptor;

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    /**
     * 静态代码
     *  静态变量 ： 每一个方法的Method对象
     *  代码块 ：为每一个方法的Method对象赋值
     */
    static Method m0;
    static Method m1;
    static Method m2;
    static MethodProxy s0;
    static MethodProxy s1;
    static MethodProxy s2;
    static {
        try {
            m0 = Proxy.class.getDeclaredMethod("save");
            m1 = Proxy.class.getDeclaredMethod("save", int.class);
            m2 = Proxy.class.getDeclaredMethod("save", long.class);

            s0 = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
            s1 = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
            s2 = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }


    // >>>>>>>>>>>>>>>>>>>>>>>>>>> 不带增强功能的方法
    public void saveSuper() {
        super.save();
    }
    public void saveSuper(int i) {
        super.save(i);
    }
    public void saveSuper(long i) {
        super.save(i);
    }
    // >>>>>>>>>>>>>>>>>>>>>>>>>>> 带增强功能的方法
    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this, m0, new Object[0], s0);
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, m1, new Object[]{i}, s1);
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    @Override
    public void save(long i) {
        try {
            methodInterceptor.intercept(this, m1, new Object[]{i}, s2);
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
}
